package com.ydj.framework.third.oss;

import cn.hutool.http.HttpUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.VoidResult;
import com.ydj.AppEnvironment;
import com.ydj.framework.exception.CommonException;
import com.ydj.framework.third.oss.res.TransferToOssByUrlDto;
import com.ydj.framework.utils.CloseUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;

@Slf4j
@Component
public class OssManager {
    @Value("${ali.oss.endpoint}")
    private String endpoint;
    @Value("${ali.accessKeyId}")
    private String accessKeyId;
    @Value("${ali.accessKeySecret}")
    private String accessKeySecret;
    @Value("${ali.oss.bucketName}")
    private String bucketName;
    @Getter
    @Value("${ali.oss.baseUrl}")
    private String baseUrl;


    @Autowired
    private AppEnvironment appEnvironment;

    /**
     *
     * @param objectName OSS里的路径，不包含Bucket名。例如 exampledir/exampleobject.txt
     */
    public String uploadFile(byte[] content, String objectName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content));

            // 如果需要上传时设置存储类型和访问权限，请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 设置该属性可以返回response。如果不设置，则返回的response为空。
            putObjectRequest.setProcess("true");
            // 上传字符串。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            // 如果上传成功，则返回200。
            System.out.println(result.getResponse().getStatusCode());
            return baseUrl + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

    /**
     *
     * @param objectName OSS里的路径，不包含Bucket名。例如 exampledir/exampleobject.txt
     */
    public boolean uploadByUrl(String srcUrl, String objectName) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        InputStream inputStream = null;
        try {
            URL url = new URL(srcUrl);
            inputStream = url.openStream();

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);

            // 如果需要上传时设置存储类型和访问权限，请参考以下示例代码。
//             ObjectMetadata metadata = new ObjectMetadata();
//             metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//             metadata.setObjectAcl(CannedAccessControlList.PublicRead);
//             putObjectRequest.setMetadata(metadata);

            // 设置该属性可以返回response。如果不设置，则返回的response为空。
            putObjectRequest.setProcess("true");
            // 上传字符串。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            // 如果上传成功，则返回200。
            if (result.getResponse().getStatusCode() != 200) {
                log.error("通过URL上传OSS图片错误。status code={}, srcUrl={}, objectName={}", result.getResponse().getStatusCode(), srcUrl, objectName);
                CommonException.throwException("通过URL上传OSS图片失败, status code=" + result.getResponse().getStatusCode());
            } else {
                log.info("通过URL上传OSS图片成功。srcUrl={}, objectName={}", srcUrl, objectName);
                return true;
            }
        } catch (Exception oe) {
            log.error("通过URL上传OSS图片失败", oe);
        } finally {
            CloseUtil.close(inputStream);
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return false;
    }

    public void delete(String url) throws Exception {
        if (StringUtils.isBlank(url)) {
            return;
        }
        String objectName = url;
        if (objectName.startsWith(baseUrl)) {
            objectName = objectName.substring(baseUrl.length());
        }

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 删除文件或目录。如果要删除目录，目录必须为空。
            VoidResult result = ossClient.deleteObject(bucketName, objectName);
        } catch (Exception oe) {
            log.error("通过删除OSS文件失败，objName=" + objectName, oe);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 通过 URL 转存文件到 OSS
     *
     * @param url           源URL
     * @param ossFullPath   OSS 全路径
     */
//     if (fileName == null) {
//        fileName = Md5Utils.encrypt(url);
//    }
    public TransferToOssByUrlDto transferToOssByUrl(String url, String ossFullPath) {
        TransferToOssByUrlDto dto = new TransferToOssByUrlDto();

        byte[] downloadData = null;
        try {
            downloadData = HttpUtil.downloadBytes(url);
        } catch (Exception ignored) {
        }
        if (downloadData == null) {
            dto.setResult(TransferToOssByUrlDto.TransferToOssResult.下载文件失败);
            return dto;
        }

        String uploadUrl = uploadFile(downloadData, ossFullPath);
        if (uploadUrl == null) {
            dto.setResult(TransferToOssByUrlDto.TransferToOssResult.上传失败);
        } else {
            dto.setResult(TransferToOssByUrlDto.TransferToOssResult.上传成功)
                    .setOssUrl(uploadUrl);
        }
        return dto;
    }

}
